﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Skybot.Extension
{
    /// <summary>
    /// 字节数据的扩展
    /// </summary>
    public static class ByteEx
    {
        /// <summary>
        /// byte 转换为十六进制字符串
        /// </summary>
        /// <param name="inBytes"></param>
        /// <returns></returns>
        public static string ToHex(this byte[] inBytes)
        {
            var stringOut = new StringBuilder("");
            foreach (var inByte in inBytes)
                stringOut.AppendFormat("{0:X2}", inByte);
            return stringOut.ToString();
        }

        /// <summary>
        /// 转换成16进制字符串
        /// </summary>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public static string ToHex(this IList<byte> bytes)
        {
            var stringOut = new StringBuilder("");
            foreach (var inByte in bytes)
                stringOut.AppendFormat("{0:X2} ", inByte);
            return stringOut.ToString();
        }


        /// <summary>
        /// 终端协议数据检测,效率大概为执行100万次 78B的包检查 需要3.0秒的时间
        /// </summary>
        /// <param name="message">单个数据包</param>
        /// <returns></returns>
        public static bool Check(this byte[] message)
        {
            //最小长度校验
            if (message.Length <= 8)
                return false;
            //无开始位检验
            if (message[0] != 0x68)
                return false;

            //无开始位校验
            if (message[5] != 0x68)
                return false;

            //无结束位检查
            if (message[message.Length - 1] != 0x16)
                return false;

            //长度计算
            var dataLenght = BitConverter.ToUInt16(message, 1);
            if (message.Length != (dataLenght + 8))
                return false;


            //校验和
            var resultint = 0;
            for (var k = 6; k < message.Length - 2; k++)
            {
                resultint += message[k];
            }
            var result = (byte)(resultint % 256);
            return result == message[message.Length - 2];
        }

        /// <summary>
        /// 验证同步数据协议 检查IncomAPI协义
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static bool CheckApi(this byte[] message)
        {
            if (message == null)
            {
                //LogProvider.Create().Write(EventType.Error, "消息为空！");
                return false;
            }
            if (message.Length == 0)
            {
                //LogProvider.Create().Write(EventType.Error, "消息为空！");
                return false;
            }
            if (message[0] != 0x7e)
            {
                //LogProvider.Create().Write(EventType.Error, "消息无开始位：" + message.ToHex());
                return false;
            }
            if (message[message.Length - 1] != 0x7e)
            {
                //LogProvider.Create().Write(EventType.Error, "消息无结束位：" + message.ToHex());
                return false;
            }
            if (message.Length < 10)//以前没有修改用户ID是12个长度
            {
                //LogProvider.Create().Write(EventType.Error, "消息总长度不符：" + message.ToHex());
                return false;
            }
            int length = BitConverter.ToUInt16(new[] { message[4], (byte)(message[3] & 0x7F) }, 0);
            var isMultiPacket = (message[3] & 0x80) >> 7;
            //var headerLength =11;
            var headerLength = 8;//11-4+1
            //取用户标识头
            byte flglen = message[5];
            headerLength = headerLength + flglen;
            //
            if (isMultiPacket == 1)
                headerLength += 4;
            //消息开始标志，消息头，分包项（可无）,校验，结束标志
            if (length != message.Length - headerLength - 2)
            {
                //LogProvider.Create().Write(EventType.Error, "消息长度不正确：" + message.ToHex());
                return false;
            }
            var temp = new byte[length];
            Array.Copy(message, headerLength, temp, 0, length);
            var result = temp.Aggregate<byte, byte>(0, (current, bt) => BitConverter.GetBytes(bt ^ current)[0]);
            if (result != message[message.Length - 2])
            {
                //LogProvider.Create().Write(EventType.Error, "校验和不正确," + message.ToHex());
                return false;
            }
            return true;
        }

        /// <summary>
        /// 验证协议是否正确
        /// </summary>
        /// <param name="message">需要验证的数据</param>
        /// <returns></returns>
        public static bool Check2(this byte[] message)
        {
            if (message == null)
            {
                //LogProvider.Create().Write(EventType.Error, "消息为空！");
                return false;
            }
            if (message.Length == 0)
            {
                //LogProvider.Create().Write(EventType.Error, "消息为空！");
                return false;
            }
            if (message[0] != 0x7e)
            {
                //LogProvider.Create().Write(EventType.Error, "消息无开始位：" + message.ToHex());
                return false;
            }
            if (message[message.Length - 1] != 0x7e)
            {
                //LogProvider.Create().Write(EventType.Error, "消息无结束位：" + message.ToHex());
                return false;
            }
            if (message.Length < 12)
            {
                //LogProvider.Create().Write(EventType.Error, "消息总长度不符：" + message.ToHex());
                return false;
            }
            int length = BitConverter.ToUInt16(new[] { message[4], (byte)(message[3] & 0x7F) }, 0);
            var isMultiPacket = (message[3] & 0x80) >> 7;
            var headerLength = 11;
            if (isMultiPacket == 1)
                headerLength += 4;
            //消息开始标志，消息头，分包项（可无）,校验，结束标志
            if (length != message.Length - headerLength - 2)
            {
                //LogProvider.Create().Write(EventType.Error, "消息长度不正确：" + message.ToHex());
                return false;
            }
            var temp = new byte[length];
            Array.Copy(message, headerLength, temp, 0, length);
            var result = temp.Aggregate<byte, byte>(0, (current, bt) => BitConverter.GetBytes(bt ^ current)[0]);
            if (result != message[message.Length - 2])
            {
                //LogProvider.Create().Write(EventType.Error, "校验和不正确," + message.ToHex());
                return false;
            }
            return true;
        }

        /// <summary>
        /// 取数据帧 从传入的数据中获取一个 部标协义
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] GetFrame(this List<Byte> message)
        {
            if (message.Count <= 0) return null;
            var beginIndex = -1;
            var endIndex = -1;
            for (var i = 0; i < message.Count; i++)
            {
                if (beginIndex == -1)
                {
                    if (message[i] == 0x7e)
                    {
                        beginIndex = i;
                    }
                }
                else if (endIndex == -1)
                {
                    if (message[i] == 0x7e)
                    {
                        endIndex = i;
                        if (endIndex == beginIndex + 1)
                        {
                            beginIndex = endIndex;
                            endIndex = -1;
                            continue;
                        }
                        break;
                    }
                }
            }
            byte[] frameMessage = null;
            if (beginIndex != -1 && endIndex != -1)
            {
                var len = endIndex - beginIndex + 1;
                //取字节数据
                frameMessage = message.GetRange(beginIndex, len).ToArray();
                if (beginIndex > 0)
                {
                    var errorMessage = message.GetRange(0, beginIndex + 1);
                    //LogProvider.Create().Write(EventType.Warning, string.Format("{0},无效数据  A-{1}", 1002, errorMessage.ToHex()));
                }
                message.RemoveRange(0, beginIndex + len);
            }
            else if (beginIndex == -1 && endIndex == -1)
            {
                //LogProvider.Create().Write(EventType.Warning, string.Format("{0},无效数据  B-{1}", 1002, message.ToHex()));
                message.Clear();

            }
            else if (beginIndex != -1 && endIndex == -1)
            {
                //LogProvider.Create().Write(EventType.Warning, string.Format("{0},无效数据 C-{1}", 1002, message.ToHex(0, beginIndex + 1)));
                message.RemoveRange(0, beginIndex + 1);
            }
            return frameMessage == null ? null : frameMessage.Decape();
        }


        #region 从TCP数据中拆包 x68->x67 02

        /// <summary>
        /// 取数据帧 从传入的数据中获取一个 定义协义
        /// 还原
        /// 0x67 0x01 ->0x67,
        /// 0x67 0x02 ->0x68,
        /// 0x67 0x03 ->0x16,
        /// 如果 没有找到返回null
        /// </summary>
        /// <param name="message">协义数据</param>
        /// <returns>返回一个数据,如果 没有找到返回null</returns>
        public static byte[] GetFramex6702Tox68(this List<Byte> message)
        {
            byte[] frameMessage = null;
            if (message.Count <= 0) return null;
            var beginIndex = -1;
            var endIndex = -1;
            for (var i = 0; i < message.Count; i++)
            {
                //多个头的直接跳过
                if (message[i] == 0x68)
                {
                    beginIndex = i;
                    endIndex = -1;
                }
                else if (message[i] == 0x16)
                {
                    endIndex = i;
                    break;
                }
            }

            if (beginIndex != -1 && endIndex != -1)
            {
                var len = endIndex - beginIndex + 1;
                //取字节数据
                frameMessage = message.GetRange(beginIndex, len).ToArray().TcpReolacex6702tox68();
                if (beginIndex > 0)
                {
                    //LogProvider.Create().Write(EventType.Warning, string.Format("{0},无效数据  T.a-{1}", 1002, message.ToHex(0, beginIndex)));
                }
                message.RemoveRange(0, endIndex + 1);
            }
            else if (beginIndex == -1 && endIndex == -1)
            {
                //LogProvider.Create().Write(EventType.Warning, string.Format("{0},无效数据  T.b-{1}", 1002, message.ToHex()));
                message.Clear();
            }
            else if (beginIndex != -1 && endIndex == -1)
            {
                if (message.Count > 8*1024)
                {
                    //LogProvider.Create().Write(EventType.Warning, string.Format("{0},超过缓冲区容量的无效数据  T.c-{1}", 1002, message.ToHex()));
                    message.Clear();
                }
            }
            return frameMessage;
        }

        #endregion

        /// <summary>
        /// 同步消息转义还原
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] Decape(this byte[] message)
        {
            List<byte> escMessage = null;
            if (message != null)
            {
                escMessage = new List<byte>(message.Length);
                for (int i = 0; i < message.Length; i++)
                {
                    if (message[i] == 0x7d)
                    {
                        if ((i + 1) < message.Length)
                        {
                            if (message[i + 1] == 0x01)
                            {
                                escMessage.Add(message[i]);
                                i++;
                            }
                            else if (message[i + 1] == 0x02)
                            {
                                escMessage.Add(0x7e);
                                i++;
                            }
                        }
                        else
                        {
                            return null;
                        }
                    }
                    else
                    {
                        escMessage.Add(message[i]);
                    }
                }
            }
            return escMessage == null ? null : escMessage.ToArray();
        }


        /// <summary>
        /// 同步消息转义还原
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] Decape(this List<byte> message)
        {
            List<byte> escMessage = null;
            if (message != null)
            {
                escMessage = new List<byte>();
                for (var i = 0; i < message.Count; i++)
                {
                    if (message[i] == 0x7d)
                    {
                        if ((i + 1) < message.Count)
                        {
                            if (message[i + 1] == 0x01)
                            {
                                escMessage.Add(message[i]);
                                i++;
                            }
                            else if (message[i + 1] == 0x02)
                            {
                                escMessage.Add(0x7e);
                                i++;
                            }
                        }
                        else
                        {
                            return null;
                        }
                    }
                    else
                    {
                        escMessage.Add(message[i]);
                    }
                }
            }
            return escMessage == null ? null : escMessage.ToArray();
        }

        /// <summary>
        /// 同步消息转义
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] Escape(this byte[] message)
        {
            if (message == null) return null;
            var lst = new List<byte>(message.Length + 100) { message[0] };
            for (var i = 1; i < message.Length - 1; i++)
            {
                switch (message[i])
                {
                    case 0x7d:
                        lst.Add(0x7d);
                        lst.Add(0x01);
                        break;
                    case 0x7e:
                        lst.Add(0x7d);
                        lst.Add(0x02);
                        break;
                    default:
                        lst.Add(message[i]);
                        break;
                }
            }
            lst.Add(message[message.Length - 1]);
            return lst.ToArray();
        }


        /// <summary>
        /// 转义
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static byte[] Escape(this List<byte> message)
        {
            if (message == null) return null;
            var lst = new List<byte>(message.Count + 100) { message[0] };
            for (var i = 1; i < message.Count - 1; i++)
            {
                switch (message[i])
                {
                    case 0x7d:
                        lst.Add(0x7d);
                        lst.Add(0x01);
                        break;
                    case 0x7e:
                        lst.Add(0x7d);
                        lst.Add(0x02);
                        break;
                    default:
                        lst.Add(message[i]);
                        break;
                }
            }
            lst.Add(message[message.Count - 1]);
            return lst.ToArray();
        }


        /// <summary>
        /// 转换成十六进制
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public static string ToHex(this List<byte> message)
        {
            if (message == null) return string.Empty;
            var str = new StringBuilder();
            foreach (var t in message)
            {
                str.Append(string.Format("{0:X2} ", t));
            }
            return str.ToString();
        }



        /// <summary>
        /// 转换成十六进制
        /// </summary>
        /// <param name="message"></param>
        /// <param name="index"> </param>
        /// <param name="length"> </param>
        /// <returns></returns>
        public static string ToHex(this List<byte> message, int index, int length)
        {
            if (message == null) return string.Empty;
            var str = new StringBuilder();
            for (var i = index; i < index + length; i++)
            {
                str.Append(string.Format("{0:X2} ", message[i]));
            }
            return str.ToString();
        }
    }
}
